# -*- coding: utf-8 -*-

"""
# @Time    : 2023/8/15 10:32 
# @Author  : Huangjinlong
# @Description    : 
"""
import redis
from threading import Lock
from application.settings import REDIS_CACHE
from redis.retry import Retry
from redis.backoff import ExponentialBackoff


class RedisManager:
    """
    Redis数据库管理类
    :author Mabin
    使用示例(结合with)：
    test_model = RedisManager()
    with test_model.get_connection() as r:
        r.hset("1", "2", "3")

    使用示例（依次调用）
    test_model = RedisManager()
    r = test_model.get_connection()
    r.set('key', 'value')
    """
    _instances = {}  # 存储不同URI的连接实例
    _lock = Lock()  # 线程安全锁

    def __new__(cls, connect_key="default"):
        """
        单例核心逻辑
        :author Mabin
        :param str connect_key:数据库连接标识
        """
        if connect_key not in cls._instances:
            # 不存在对应连接标识的实例
            with cls._lock:
                # 实例化
                instance = super().__new__(cls)

                # 初始化数据库连接
                instance._init_connection(connect_key=connect_key)

                # 存储
                cls._instances[connect_key] = instance

        # 返回实例
        return cls._instances[connect_key]

    def _init_connection(self, connect_key="default"):
        """
        初始化新连接(连接池)
        :author Mabin
        :param str connect_key:数据库连接标识
        :return:
        """
        # 获取数据库链接配置
        connect_config = REDIS_CACHE.get(connect_key, None)
        if not connect_config:
            raise Exception(f"创建Redis数据库连接时，未查询到数据库链接配置！{connect_key}")

        # 创建连接池（自动管理连接池）
        self.redis_pool = redis.ConnectionPool(
            host=connect_config["HOST"],
            port=connect_config["PORT"],
            db=connect_config["DB"],
            password=connect_config["PASSWD"],
            max_connections=connect_config["MAX_CONNECTIONS"],  # 最大连接数
            socket_connect_timeout=connect_config["SOCKET_CONNECT_TIMEOUT"],  # 连接超时(秒)
            socket_timeout=connect_config["SOCKET_TIMEOUT"],  # 操作超时
            decode_responses=True,  # 自动解码返回字符串
            health_check_interval=150,  # 健康检查间隔
            socket_keepalive=True,
            retry_on_timeout=False,  # 禁用操作超时的重试
            # retry=Retry(ExponentialBackoff(), 3)  # 指数退避重试策略，最多重试3次
        )

    def get_connection(self):
        """
        从连接池中获取连接
        :author Mabin
        :return:
        """
        return redis.Redis(connection_pool=self.redis_pool)


def get_redis_connection(redis_key='default'):
    """
    获取redis连接池(此函数为了与Django的redis获取方法保持一致而设置)
    :author Mabin
    :param redis_key 指定连接池的配置key
    :return:
    """
    # 获取配置
    redis_model = RedisManager(connect_key=redis_key)

    # 无需手动关闭连接，连接将在使用完毕后自动归还到连接池
    return redis_model.get_connection()
